﻿using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Collections.Generic;

using CustomTypeDescriptor = Jayrock.Json.Conversion.CustomTypeDescriptor;
using Jayrock.Json;
using Jayrock.Json.Conversion;
using Jayrock.Json.Conversion.Converters;

namespace N2.Jayrock.Json.Converters
{
	public sealed class ContentItemImporter : ImporterBase
	{
		private readonly IObjectMemberImporter[] _importers;

		public ContentItemImporter() : this(typeof(ContentItem)) { }

		public ContentItemImporter(Type type) :
			base(type) { }

		protected override object ImportFromObject(ImportContext context, JsonReader reader)
		{
			Debug.Assert(context != null);
			Debug.Assert(reader != null);

			reader.Read();

			ContentItem o = null;

			var _sourceProperties = new Dictionary<string, object>();
			Type _type = null;
			int? _itemId = default(int?);
			int? _parentId = default(int?);

			PropertyDescriptorCollection _properties = null;
			
			while (reader.TokenClass != JsonTokenClass.EndObject) {
				string memberName = reader.ReadMember();

				if (null == o) {

					if (string.Equals(memberName, "id", StringComparison.OrdinalIgnoreCase)) {
						_itemId = (int)context.Import(reader);
						continue;
					}

					if (string.Equals(memberName, "__metadata", StringComparison.OrdinalIgnoreCase)) {
						reader.Read();
						var _memberName = reader.ReadMember();

						if (string.Equals(_memberName, "type", StringComparison.OrdinalIgnoreCase)) {
							var _typeName = context.Import(reader) as string;
							if (!string.IsNullOrEmpty(_typeName)) {
								_type = N2.Utility.TypeFromName(_typeName);
							}
						}
						reader.Read();
						continue;
					}

					if (string.Equals(memberName, "parent", StringComparison.OrdinalIgnoreCase)) {
						reader.Read();
						var _memberName = reader.ReadMember();

						if (string.Equals(_memberName, "__deferred", StringComparison.OrdinalIgnoreCase)) {
							reader.Read();
							if (string.Equals(reader.ReadMember(), "id", StringComparison.OrdinalIgnoreCase)) {
								_parentId = context.Import<int>(reader);
							}
							reader.Read();
						}
						reader.Read();
						continue;
					}

					if (_itemId.HasValue && _itemId.Value > 0) {
						o = N2.Context.Persister.Get(_itemId.Value);
					}

					if (_parentId.HasValue && _parentId.Value > 0 && null != _type) {
						var _parent = N2.Context.Persister.Get(_parentId.Value);
						o = N2.Context.Definitions.CreateInstance(_type, _parent);
					}

					if(null != o) {
						_properties = TypeDescriptor.GetProperties(o);
					}
				}
				
				//reader.StepOut
				PropertyDescriptor property = _properties.Find(memberName, true);

				//
				// Check if the property defines a custom import scheme.
				// If yes, ask it to import the value into the property 
				// and then continue with the next.
				//
				///TODO doesn't work yet
				if (_importers != null) {
					int index = _properties.IndexOf(property);

					IObjectMemberImporter importer = _importers[index];

					if (importer != null) {
						importer.Import(context, reader, o);
						continue;
					}
				}

				//
				// Import from reader based on the property type and 
				// then set the value of the property.
				//

				_sourceProperties.Add(memberName, context.Import(property.PropertyType, reader));
			}

			if (null != o) {
				foreach (var _kvp in _sourceProperties) {
					var _property = _properties.Find(_kvp.Key, true);
					if (null != _property) {
						_property.SetValue(o, _kvp.Value);
					}
				}

				//N2.Context.Persister.Save(o);
			}

			return o;
		}
	}
}
